#include "dspSimulator/instruction/AND.h"

std::shared_ptr<Instruction> AND::decode(std::shared_ptr<InstInfo> instInfo, u64 baseCycle) {
    std::shared_ptr<AND> _and;
    auto dspInstInfo = std::dynamic_pointer_cast<DspInstInfo>(instInfo);
    bool isStandardInst = dspInstInfo->isStandardInstruction();
    if (isStandardInst) {
        auto data = vectorToBitSet<32>(dspInstInfo->getBits());
        if (checkBits<10>(data, 2, 0b1001111100) && existStandardCondition(data)) {
            // Opcode for .D Unit, 2 src   scst5,xop2,dst
            _and = std::make_shared<AND>(dspInstInfo->getAddress(), baseCycle);
            _and->creg_z = extractBits<4>(data, 28);
            u32 dst = extractBits<5>(data, 23).to_ulong();
            u32 src2 = extractBits<5>(data, 18).to_ulong();
            u32 cst = extractBits<5>(data, 13).to_ulong();
            bool x = data[12];
            bool s = data[1];
            _and->p = data[0];
            if (s == 0) {
                _and->funcUnit = FuncUnit::D1;
            } else {
                _and->funcUnit = FuncUnit::D2;
            }
            _and->m_op1 = std::make_shared<Immediate32>(extractBitsAndToInt<5>(cst));
            _and->m_op2 = std::make_shared<SingleReg>(getSrc2Reg32Kind(src2, s, x));
            _and->m_op3 = std::make_shared<SingleReg>(getDstReg32Kind(dst, s));
        }
    }
    return _and;
}

void
AND::generateIR(std::shared_ptr<IRGenerator> irGenerator, llvm::Function *function,
                DspInstruction::RegCopy &regCopy) {
    if (funcUnit == FuncUnit::D1 || funcUnit == FuncUnit::D2) {
        generateIRInD(irGenerator, function, regCopy);
    }
}

void AND::generateIRInD(std::shared_ptr<IRGenerator> irGenerator, llvm::Function *function,
                        DspInstruction::RegCopy &regCopy) {
    auto irBuilder = irGenerator->getLLVMIRBuilder();
    auto module = irGenerator->getLLVMModule();
    if (!isCompactInstruction) {
        auto cst = std::dynamic_pointer_cast<Immediate32>(m_op1);
        auto src2Reg = std::dynamic_pointer_cast<SingleReg>(m_op2);
        auto dstReg = std::dynamic_pointer_cast<SingleReg>(m_op3);
        if (cst && src2Reg && dstReg) {
            auto src2Val = regCopy[getRegName(src2Reg->getReg())];
            auto result = irBuilder->CreateAnd(src2Val, irBuilder->getInt32(cst->getData()));
            auto dstRegPtr = module->getNamedGlobal(getRegName(dstReg->getReg()));
            irBuilder->CreateStore(result, dstRegPtr);
        }
    }
}

std::string AND::toString() {
    std::string str;
    auto cst = std::dynamic_pointer_cast<Immediate32>(m_op1);
    if (cst) {
        str = m_name + " " + FuncUnitName[static_cast<u32>(funcUnit)] + " " + dec2hex(cst->getData()) + "," + m_op2->toString() +
                "," + m_op3->toString();
    }
    return str;
}
